﻿namespace StockSharp.Algo.Indicators.Trend
{
	using System.ComponentModel;

	using Candles;

	using StockSharp.Algo.Indicators.Misc;

	/// <summary>
	/// Optimal Tracking.
	/// </summary>
	/// <remarks>
	/// Based on a Kalman Filter (Dr. R. E. Kalman, 1960)
	/// and Kalatas Tracking Index (Paul. R. Kalata, 1984)
	/// </remarks>
	[DisplayName( "OptimalTracking" )]
	[Description( "Optimal Tracking Filter published by John Ehlers" )]
	public sealed class OptimalTracking : LengthIndicator<decimal>
	{
		//Fields

		public int mult		= 4;
		decimal lambda		= 0;
		decimal alpha		= 0;
		const int _start = 1;

		decimal value1_old;
		decimal value2_old;
		decimal result_old;

		public decimal smooth_constant1;
		public decimal smooth_constant;		

		//methods

		public OptimalTracking()
		{
			Length = _start+1;	 //только 2 т.к текущая и пред свеча.
			const double x = -0.25;
			smooth_constant1 = (decimal) System.Math.Exp( x );
			smooth_constant = 1 - smooth_constant1;

			value1_old = 0;
			value2_old = 0;
			result_old = 0;
		}

		public override void Reset()
		{
			base.Reset();

			value1_old = 0;
			value2_old = 0;
			result_old = 0;

			lambda = 0;
			alpha = 0;
		}

		public override decimal OnProcess( IIndicatorValue input )
		{			
			var candle = input.GetValue<Candle>();
			decimal average = (candle.HighPrice + candle.LowPrice) / 2;
			var halfRange = (candle.HighPrice - candle.LowPrice)/2;

			Buffer.Add( average );
			var Chec1 = Buffer[Buffer.Count - 1];

			if( IsFormed ) {				
				if( Buffer.Count > Length )
					Buffer.RemoveAt( 0 );
				//Сглаженное приращение ****************************************************************************
				var avgDiff = Buffer[Buffer.Count - 1] - Buffer[Buffer.Count - 2];
				decimal smoothDiff = smooth_constant * avgDiff + smooth_constant1 * value1_old;	
				value1_old = smoothDiff;

				//Сглаженный Half Range *********************************************************************************
				
				decimal smoothRng = smooth_constant * halfRange + smooth_constant1 * value2_old;
				value2_old = smoothRng;

				//Tracking index ***********************************************************************************
				if( smoothRng != 0 ) 
					lambda = System.Math.Abs( smoothDiff / smoothRng );				

				//Alfa для альфа фильтра ***************************************************************************
				alpha = ( -lambda*lambda + (decimal) System.Math.Sqrt( (double) ( lambda*lambda*lambda*lambda + 16*lambda*lambda ) ) ) / 8;

				//Smoothed result **********************************************************************************
				var check2 = alpha*average;
				var check3 = (1 - alpha)*result_old;
				decimal result = check2 + check3;
				result_old = result;
				
				return result;
			}
			value2_old = halfRange;
			return result_old = average;			
		}
	}
}